﻿// Inner Fire 游戏引擎库
// BinaryModel - 二进制模型
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 所属层级：应用层(4)
// 将已经载入的模型进行缓存，这样就不用每次都重新载入。
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2025-01-14

#include "binary_model.h"
#include <klog.h>

namespace ifire::game {

BinaryModel::BinaryModel(Model* model) : model_(model), file_() {}

void BinaryModel::Save() {
  // 从Model的路径得到Cache文件名
  auto filename = GetCachedFilename();
  // 进入写模式
  file_.open(filename, ikit::CachedFile::OpenMode::Write);
  KLOG("Save Cached to: %s", filename.c_str());

  // 写入骨架
  model_->armature_->Save(file_);

  // 顶点
  auto& vlist = model_->svlist_;

  // 写入Mesh
  auto& submeshs = vlist.Mesh()->Submeshs();
  file_.writeInt(static_cast<int>(submeshs.size())); // Mesh的数量
  // 写入Mesh
  for (auto& i : submeshs) {
    file_.writeString(i.name.c_str());
    file_.writeInt(i.material_index);
    file_.writeInt(i.index_start);
    file_.writeInt(i.index_count);
    file_.writeInt(i.vertex_start);
    file_.writeInt(i.vertex_count);
  }
  // 写入所有的顶点信息
  auto& indices = vlist.Indices();
  file_.writeInt(static_cast<int>(indices.size()));
  file_.writeBytes(indices.data(), sizeof(uint32_t) * indices.size());
  auto& vertices = vlist.Vertices();
  file_.writeInt(static_cast<int>(vertices.size()));
  file_.writeBytes(vertices.data(), sizeof(SkinnedVertex) * vertices.size());
}

void BinaryModel::Load() {
  // 从Model的路径得到Cache文件名
  auto filename = GetCachedFilename();
  // 进入写模式
  file_.open(filename, ikit::CachedFile::OpenMode::Read);

  // 读取骨架
  model_->armature_ = std::make_unique<Armature>(file_);

  // 读取顶点
  auto& vlist = model_->svlist_;
  vlist.Init(model_->name);

  int submesh_count = file_.readInt();
  auto& submeshs = vlist.Mesh()->Submeshs();
  submeshs.resize(submesh_count);
  char buffer[64];
  for (auto& i : submeshs) {
    i.parent = vlist.Mesh();
    i.name = file_.readString(buffer);
    i.material_index = file_.readInt();
    i.index_start = file_.readInt();
    i.index_count = file_.readInt();
    i.vertex_start = file_.readInt();
    i.vertex_count = file_.readInt();
  }

  // 读取所有顶点的信息
  int index_count = file_.readInt();
  auto& indices = vlist.Indices();
  indices.resize(index_count);
  file_.readBytes(indices.data(), index_count * sizeof(uint32_t));
  int vertex_count = file_.readInt();
  auto& vertices = vlist.Vertices();
  vertices.resize(vertex_count);
  file_.readBytes(vertices.data(), vertex_count * sizeof(SkinnedVertex));
}

bool BinaryModel::IsCached() {
  auto& filename = model_->filename_;
  auto cached_filename = GetCachedFilename();
  return ikit::CachedFile::IsCachedValid(filename, cached_filename);
}

std::string BinaryModel::GetCachedFilename() const {
  return ikit::CachedFile::GetCachedFileName(model_->filename_, "model_cache");
}

} // namespace ifire::game